// lib/src/models/shipment.dart

import 'package:intl/intl.dart'; // 用于日期格式化

/// 代表运单的数据模型。
class Shipment {
  /// 运单的唯一标识号。
  late final String trackingNumber;

  /// 关联的客户代码。
  final String customerCode;

  /// 货物简称，不超过16个字符。
  final String cargoShortName;

  /// 包裹数量。
  final int packageCount;

  /// 运单创建时间 (UTC)。
  final DateTime createdTimeUtc;

  /// 发货港口所在时区相对于UTC的小时偏移量。
  final int departurePortTimezoneOffsetHours;

  /// 货物运输方式。
  /// 通常存储为标准的英文值，如 "Sea", "Air"，以便作为翻译的键。
  final String transportMode;

  /// 货物预计运输时间（天数）。
  final int estimatedTransitDays;

  /// 运单状态。
  /// 建议存储为标准的英文状态值，如 "Not Shipped", "Shipped", "Arrived", "Picked Up"。
  /// 这些英文值可以作为翻译的键。
  String status;

  /// 货物明细描述。
  final String cargoDetails;

  /// 运单发出日期 (UTC)。可选。
  DateTime? shippedDateUtc;

  /// 运单预计到达日期 (UTC)。可选，可根据发出日期和预计运输天数计算。
  DateTime? estimatedArrivalDateUtc;

  /// 运单实际到达日期 (UTC)。可选。
  DateTime? actualArrivalDateUtc;

  /// 运单提货日期 (UTC)。可选。
  DateTime? pickupDateUtc;

  /// 公共构造函数，用于创建 *新的* 运单实例。
  /// 运单号 (trackingNumber) 会自动生成。
  /// 运单创建时间 (createdTimeUtc) 会自动设为当前UTC时间。
  Shipment({
    required this.customerCode,
    required this.cargoShortName,
    required this.packageCount,
    required this.departurePortTimezoneOffsetHours,
    required this.transportMode, // 应传入英文标准值, e.g., "Sea"
    required this.estimatedTransitDays,
    this.status = "Not Shipped", // 默认状态使用英文标准值
    required this.cargoDetails,
    this.shippedDateUtc,
    this.actualArrivalDateUtc,
    this.pickupDateUtc,
  }) : createdTimeUtc = DateTime.now().toUtc() {
    trackingNumber = _generateTrackingNumber();
    // 如果在创建时就提供了发货日期，则计算预计到达日期
    if (shippedDateUtc != null) {
      estimatedArrivalDateUtc = shippedDateUtc!.add(
        Duration(days: estimatedTransitDays),
      );
    }
  }

  /// 私有命名构造函数，用于从持久化数据（如JSON）恢复对象时使用。
  /// 这种情况下，trackingNumber 和 createdTimeUtc 是已知的。
  Shipment._internal({
    required this.trackingNumber,
    required this.customerCode,
    required this.cargoShortName,
    required this.packageCount,
    required this.createdTimeUtc,
    required this.departurePortTimezoneOffsetHours,
    required this.transportMode,
    required this.estimatedTransitDays,
    required this.status,
    required this.cargoDetails,
    this.shippedDateUtc,
    this.estimatedArrivalDateUtc,
    this.actualArrivalDateUtc,
    this.pickupDateUtc,
  });

  /// 私有辅助方法，用于生成运单号。
  String _generateTrackingNumber() {
    // 使用更精确到秒的时间戳，以减少在高并发情况下生成重复单号的概率（尽管在此应用场景下并发不高）
    final String timestamp = DateFormat(
      'yyyyMMddHHmmss',
    ).format(createdTimeUtc.toLocal()); // 使用 toLocal() 确保时间戳基于本地时区，然后格式化
    return '${customerCode}_${cargoShortName.replaceAll(' ', '')}_${packageCount}_$timestamp'; // 移除了货物简称中的空格
  }

  /// 更新运单状态。
  /// newStatus 应该是英文标准状态值。
  void updateStatus(String newStatusEnglishKey) {
    status = newStatusEnglishKey; // 直接更新为英文键

    // 根据新状态自动设置相关日期（如果它们当前为null）
    // 注意：这里的比较也应该用英文键
    if (newStatusEnglishKey == "Shipped" && shippedDateUtc == null) {
      shippedDateUtc = DateTime.now().toUtc();
      estimatedArrivalDateUtc = shippedDateUtc!.add(
        Duration(days: estimatedTransitDays),
      );
    } else if (newStatusEnglishKey == "Arrived" &&
        actualArrivalDateUtc == null) {
      actualArrivalDateUtc = DateTime.now().toUtc();
    } else if (newStatusEnglishKey == "Picked Up" && pickupDateUtc == null) {
      pickupDateUtc = DateTime.now().toUtc();
    }
    // 注意：如果日期已经由用户手动设置，则此处不会覆盖它们。
    // Service 层的状态回滚逻辑会在此方法调用前清除不应再存在的日期。
  }

  /// 从Map对象创建Shipment实例的工厂构造函数。
  factory Shipment.fromMap(Map<String, dynamic> map) {
    return Shipment._internal(
      trackingNumber: map['trackingNumber'] as String,
      customerCode: map['customerCode'] as String,
      cargoShortName: map['cargoShortName'] as String,
      packageCount: map['packageCount'] as int,
      createdTimeUtc: DateTime.parse(map['createdTimeUtc'] as String),
      departurePortTimezoneOffsetHours:
          map['departurePortTimezoneOffsetHours'] as int,
      transportMode: map['transportMode'] as String, // 假设JSON中存储的是英文标准值
      estimatedTransitDays: map['estimatedTransitDays'] as int,
      status: map['status'] as String, // 假设JSON中存储的是英文标准值
      cargoDetails: map['cargoDetails'] as String,
      shippedDateUtc:
          map['shippedDateUtc'] != null
              ? DateTime.parse(map['shippedDateUtc'] as String)
              : null,
      estimatedArrivalDateUtc:
          map['estimatedArrivalDateUtc'] != null
              ? DateTime.parse(map['estimatedArrivalDateUtc'] as String)
              : null,
      actualArrivalDateUtc:
          map['actualArrivalDateUtc'] != null
              ? DateTime.parse(map['actualArrivalDateUtc'] as String)
              : null,
      pickupDateUtc:
          map['pickupDateUtc'] != null
              ? DateTime.parse(map['pickupDateUtc'] as String)
              : null,
    );
  }

  /// 将Shipment实例转换为Map对象。
  Map<String, dynamic> toMap() {
    return {
      'trackingNumber': trackingNumber,
      'customerCode': customerCode,
      'cargoShortName': cargoShortName,
      'packageCount': packageCount,
      'createdTimeUtc': createdTimeUtc.toIso8601String(),
      'departurePortTimezoneOffsetHours': departurePortTimezoneOffsetHours,
      'transportMode': transportMode, // 保存英文标准值
      'estimatedTransitDays': estimatedTransitDays,
      'status': status, // 保存英文标准值
      'cargoDetails': cargoDetails,
      'shippedDateUtc': shippedDateUtc?.toIso8601String(),
      'estimatedArrivalDateUtc': estimatedArrivalDateUtc?.toIso8601String(),
      'actualArrivalDateUtc': actualArrivalDateUtc?.toIso8601String(),
      'pickupDateUtc': pickupDateUtc?.toIso8601String(),
    };
  }

  @override
  String toString() {
    // 使用UTC时间进行标准输出，避免时区混淆
    final createdTimeFormatted = DateFormat(
      'yyyy-MM-dd HH:mm:ss',
    ).format(createdTimeUtc);
    // status 已经是英文键
    return 'Shipment(trackingNumber: $trackingNumber, customerCode: $customerCode, cargoShortName: $cargoShortName, status: $status, createdTimeUtc: $createdTimeFormatted UTC)';
  }
}
